<template>
  <div class="flow-editor" @wheel="handleWheel" @keydown="handleKeyDown" @keyup="handleKeyUp" @mousedown="startPan"
    @mousemove="handlePan" @mouseup="stopPan" @mouseleave="stopPan" tabindex="0">
    <!-- 左侧节点面板 -->
    <div v-if="!isPview" class="node-palette">
      <div>
        <slot name="left"></slot>
      </div>
      <div :style="{
        width: node.width + 'px',
        height: node.height + 'px',
        backgroundColor: node.color,
        borderRadius: node.type === 'start' ? '50%' : '4px',
      }" v-for="node in nodeTypes" :key="node.type" class="palette-node" draggable="true"
        @dragstart="startDrag($event, node)">
        {{ node.label }}
      </div>
    </div>

    <!-- 画布容器 -->
    <div class="flow-canvas-container" ref="canvasContainer" :style="{
      cursor: isPanning
        ? 'grabbing'
        : spaceKeyPressed
          ? 'grab'
          : isSelecting
            ? 'crosshair'
            : isDrawingConnection
              ? 'crosshair'
              : 'default',
    }">
      <div v-if="!isPview" class="scale-control">
        <span style="cursor: pointer" @click="zoomIn"> + </span>
        <div style="width: 50px; font-size: 14px; text-align: center">
          {{ Math.round(canvasScale * 100) }}%
        </div>

        <span style="cursor: pointer" @click="zoomOut"> - </span>
        <Cbutton size="small" @click="resetZoom">重置</Cbutton>
        <!-- 新增：撤回和重做按钮 -->

        <span @click="undo" :disabled="historyIndex < 0" style="margin-left: 10px; cursor: pointer"
          :style="{ opacity: historyIndex < 0 ? 0.5 : 1 }">
          ←
        </span>

        <span @click="redo" :disabled="historyIndex >= history.length - 1" style="cursor: pointer"
          :style="{ opacity: historyIndex >= history.length - 1 ? 0.5 : 1 }">
          →
        </span>
        <!-- 新增：连线方式选择下拉框 -->
        <select size="small" v-if="isConnectionType" v-model="connectionType" style="width: 120px; margin-left: 10px"
          placeholder="连线方式">
          <option label="曲线" value="curve"></option>
          <option label="折线" value="mindmap"></option>
        </select>
        <div class="tc">
          图层
          <div class="layer-list">
            <div v-if="nodes.length > 0">
              <div :style="{ color: selectedNodeIds.includes(value.id) ? 'red' : '' }" class="liners"
                @click="NodeDrag(value)" v-for="(value, index) in nodes" :key="value.id">
                {{ value.label }}
              </div>
            </div>
            <div style="padding: 10px 15px" v-else>请选择图层</div>
          </div>
        </div>
        <div class="czsm">
          操作说明
          <div class="layer-list">
            <div>
              <div :style="{ color: selectedNodeIds.includes(value.id) ? 'red' : '' }" class="liners"
                v-for="(value, index) in czsm" :key="index">
                {{ value }}
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- 画布 -->
      <div class="flow-canvas" ref="canvas" :style="{
        backgroundImage: `url(${bg})`,
        transform: `translate(${canvasOffset.x}px, ${canvasOffset.y}px) scale(${canvasScale})`,
        transformOrigin: '0 0',
        width: `${canvasSize.width}px`,
        height: `${canvasSize.height}px`,
      }" @dragover.prevent @drop="handleDrop" @mousedown="handleCanvasClick" @mouseup="endConnection"
        @contextmenu.prevent>
        <!-- 校准线 -->
        <div v-for="guide in alignmentGuides" :key="guide.id" :style="{
          position: 'absolute',
          left: guide.left + 'px',
          top: guide.top + 'px',
          width: guide.width + 'px',
          height: guide.height + 'px',
          background: guide.color,
          zIndex: 40,
        }" class="alignment-guide"></div>
        <!-- 连接线容器 -->
        <svg class="connections-container" :width="canvasSize.width" :height="canvasSize.height">
          <g>
            <!-- 所有连接线 -->
            <path v-for="connection in connections" :key="connection.id" :d="getConnectionPathByType(connection)"
              :stroke-width="selectedConnectionId === connection.id ? 5 : 5"
              :stroke="selectedConnectionId === connection.id ? '#000' : '#3b82f6'" fill="none" class="connection-line"
              @click.stop="selectConnection(connection.id)" style="cursor: pointer" />
          </g>

          <!-- 临时连接线（正在绘制中） -->
          <path v-if="isDrawingConnection" :d="getTemporaryConnectionPath()" stroke="#666" stroke-width="2"
            stroke-dasharray="5,5" fill="none" />
        </svg>

        <!-- 可拖拽节点 -->
        <div v-for="node in nodes" :key="node.id" class="flow-node" :class="{
          selected: selectedNodeIds.includes(node.id),
          dragging: draggingNodeIds.includes(node.id),
          resizing: isResizing,
          'connection-source': isDrawingConnection && connectionSourceId === node.id,
        }" :id="node.id" :style="{
          left: `${node.x}px`,
          top: `${node.y}px`,
          width: `${node.width}px`,
          height: `${node.height}px`,
          backgroundColor: node.color,
          borderRadius: node.type === 'start' ? '50%' : '4px',
        }" @mousedown.stop="startNodeDrag($event, node)" @click.stop="selectNode($event, node)"
          @dblclick="editNode(node)" @mousedown.right.prevent="startConnection(node)">
          <slot :node="node" name="content"></slot>
          <slot v-if="node.type === 'slot'" :node="node" :name="node.slotName"></slot>

          <div v-else-if="node.type === 'html'" v-html="node.target"></div>
          <div v-else class="node-label" style="position: absolute; top: -30px">
            {{ node.label }}
          </div>
          <!-- 选中框 -->
          <div class="selection-box" v-if="selectedNodeIds.includes(node.id)">
            <!-- 大小调整控制点 -->
            <div class="resize-handle resize-handle-se" @mousedown.stop="startResize($event, node, 'se')"></div>
            <div class="resize-handle resize-handle-sw" @mousedown.stop="startResize($event, node, 'sw')"></div>
            <div class="resize-handle resize-handle-ne" @mousedown.stop="startResize($event, node, 'ne')"></div>
            <div class="resize-handle resize-handle-nw" @mousedown.stop="startResize($event, node, 'nw')"></div>
          </div>
        </div>

        <!-- 选择框 -->
        <div v-if="selectionBox.show" class="selection-box-area" :style="{
          '--box-x': `${selectionBoxs.x}px`,
          '--box-y': `${selectionBoxs.y}px`,
          '--box-width': `${selectionBoxs.width}px`,
          '--box-height': `${selectionBoxs.height}px`,
        }"></div>
      </div>
    </div>

    <!-- 配置面板 -->
    <div v-if="isShowConfig && !isPview" class="config-panel">
      <div v-if="selectedNodeIds.length === 1 && isRightConfig">
        <slot name="right-config" :selectNode="selectNodes"></slot>
      </div>
      <!-- <Cbutton @click="saveNodes">预览</Cbutton> -->
      <div v-else-if="selectedNodeIds.length === 1">
        <p>节点名称：<Cinput v-model:value="selectNodes.label" placeholder="节点名称"></Cinput>
        </p>
        <p>
          x：<Cinput type="number" v-model:value="selectNodes.x" placeholder="节点名称"></Cinput>
        </p>
        <p>
          y：<Cinput type="number" v-model:value="selectNodes.y" placeholder="节点名称"></Cinput>
        </p>
        <p>宽度：<Cinput type="number" v-model:value="selectNodes.width"></Cinput>
        </p>
        <p>高度：<Cinput type="number" v-model:value="selectNodes.height"></Cinput>
        </p>
      </div>

      <div v-else-if="!selectedNodeIds.length" style="color: #999; font-size: 14px">
        <p>画布宽度：<Cinput type="number" v-model:value="canvasSize.width"></Cinput>
        </p>

        <p>画布高度：<Cinput type="number" v-model:value="canvasSize.height"></Cinput>
        </p>
      </div>
      <div v-else style="color: #999; font-size: 14px">
        <p>宽度：<Cinput type="number" @change="setChange" v-model:value="nodeWidth"></Cinput>
        </p>
        <p>高度：<Cinput type="number" @change="setChange" v-model:value="nodeHeight"></Cinput>
        </p>
        <p>
          对齐方式:
          <CradioGroup @change="setAlignment" v-model:model-value="alignment" :options="[
            { label: '左', value: 'left' },
            { label: '右', value: 'right' },
            { label: '上', value: 'top' },
            { label: '下', value: 'bottom' },
          ]"></CradioGroup>
        </p>
      </div>
      <!-- 新增：显示选中的连线信息 -->
      <div v-if="selectedConnectionId">
        <p>已选中一条连线</p>
        <Cbutton type="danger" size="small" @click="deleteSelectedConnection">删除连线</Cbutton>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import Cbutton from './C/Cbutton/Cbutton.vue'
import Cinput from './C/Cinput/Cinput.vue'
import CradioGroup from './C/CradioGroup/CradioGroup.vue'
import { ref, onMounted, onUnmounted, watch, defineExpose, h } from 'vue'
import { Plus, Minus, RefreshLeft, RefreshRight } from '@element-plus/icons-vue'
import { AlignmentGuides, Connections, Nodes, SelectionBoxs, Clipboard, Historys } from './type'
type NodeType = {
  type: string
  label: string
  width: number
  height: number
  color: string
}

type Props = {
  isPview: boolean//预览模式
  isPanning: boolean //是否正在拖动
  isZoom: boolean//是否缩放
  canvasSize: {
    width: number
    height: number
  }//画布的宽高
  bg: string //背景图片
  isConnectionType: boolean //是否开启连线
  nodeTypes: NodeType[] //节点类型
  width: number //画布宽度
  height: number //画布高度
  connections: any[] //连接线数据
  isShowConfig: boolean //是否显示配置面板
  isCzsm: boolean //是否显示操作说明
  isRightConfig: boolean //是否显示右侧配置面板（自定义--选择单独节点后显示自定义配置面板）
  nodesValue: {
    //节点数据
    type: Array
    default: () => []
  }
}
const props = withDefaults(defineProps<Props>(), {
  bg: '',
  isZoom: true,
  isPanning: true,
  isPview: false,
  isConnectionType: false,
  nodesValue: [],
  connections: [],
  canvasSize: {
    width: 1980,
    height: 1080
  },
  width: 1920,
  height: 1080,
  isShowConfig: true,
  isCzsm: true,
})
const czsm = [
  '鼠标滚轮缩放和放大',
  '按住空格键平移画布',
  '按住左键拖拽节点',
  '按住右键拖拽连线',
  '选中后点击角落调整大小',
  '按住ctrl调整大小可以比例放大缩小',
  '删除键删除节点',
  'Ctrl+C复制节点',
  'Ctrl+V粘贴节点',
  'Ctrl+Z撤销',
  'Ctrl+Y重做',
  'ctrl+鼠标左键框选',
  '多选组件后可以在右侧选择对其方式',
]
const emit = defineEmits([
  'editNode', // 双击节点触发
  'handleDragMove', //节点移动的时候触发
  'getcanvasSize', //获取画布大小
  'getConnectionsValue', //获取连线数据
  'getNodesValue', //获取nodes节点数据
  'saveNodes', //保存节点数据
  'getNodes', //
  'copyNode',//复制节点触发
  'delNodes'//删除节点触发
])
type EditNodeData = {
  id?: string
  label?: string
  x?: number
  y?: number
  width?: number
  height?: number
  color?: string
  type?: string
}
const selectNodes = ref<EditNodeData>({})
// 节点类型定义
const nodeTypes = ref<NodeType[]>(props.nodeTypes)

// 画布节点数据
const nodes = ref<Nodes[]>([...props.nodesValue])
// console.log(props.nodesValue)
watch(
  () => props.nodesValue,
  (newVal) => {
    nodes.value = [...newVal]
  }
)

// 连接线数据
const connections = ref<Connections[]>([...props.connections])
watch(
  () => props.connections,
  (newVal) => {
    connections.value = [...newVal]
  }
)
watch(
  () => selectNodes,
  () => {
    // 加入历史记录
    saveStateToHistory()
  },
  {
    deep: true,
  }
)
const alignment = ref<AlignmentGuides[]>([])
const nodeWidth = ref<number>(props.width)
const nodeHeight = ref<number>(props.height)
// 新增：历史记录相关
const history = ref<Historys[]>([]) // 存储历史状态
const historyIndex = ref<number>(-1) // 当前历史记录索引
const MAX_HISTORY: number = 50 // 最大历史记录数量

// 保存当前状态到历史记录
const saveStateToHistory = () => {
  // 如果不是初始状态且当前有历史记录，清除当前索引之后的历史
  if (historyIndex.value < history.value.length - 1) {
    history.value = history.value.slice(0, historyIndex.value + 1)
  }

  // 保存当前状态的深拷贝
  const currentState = {
    nodes: JSON.parse(JSON.stringify(nodes.value)),
    connections: JSON.parse(JSON.stringify(connections.value)),
  }

  history.value.push(currentState)

  // 限制历史记录数量
  if (history.value.length > MAX_HISTORY) {
    history.value.shift()
  }

  historyIndex.value = history.value.length - 1
}

// 初始化时保存一次状态
saveStateToHistory()

// 撤回操作
const undo = () => {
  if (historyIndex.value <= 0) return

  historyIndex.value--
  const prevState = history.value[historyIndex.value]
  nodes.value = JSON.parse(JSON.stringify(prevState.nodes))
  connections.value = JSON.parse(JSON.stringify(prevState.connections))
  // 清除选中的节点ID
  selectedNodeIds.value = []
  // 同时清除选中的连线ID（可选）
  selectedConnectionId.value = ''
  // 触发相关事件
  emit('getNodesValue', nodes.value)
  emit('getConnectionsValue', connections.value)
}

// 重做操作
const redo = () => {
  if (historyIndex.value >= history.value.length - 1) return

  historyIndex.value++
  const nextState = history.value[historyIndex.value]
  nodes.value = JSON.parse(JSON.stringify(nextState.nodes))
  connections.value = JSON.parse(JSON.stringify(nextState.connections))

  // 触发相关事件
  emit('getNodesValue', nodes.value)
  emit('getConnectionsValue', connections.value)
}

// 当前选中的节点IDs (支持多选)
const selectedNodeIds = ref([])

// 当前选中的连线ID
const selectedConnectionId = ref('')

// 连线类型（曲线或脑图折线）
const connectionType = ref('curve')

// 正在拖拽的节点IDs
const draggingNodeIds = ref([])

// 拖拽起始位置
const dragStartPos = ref({ x: 0, y: 0 })

// 节点初始位置
const nodeStartPositions = ref({})

// 画布缩放和平移状态
const canvasScale = ref(1)
const canvasOffset = ref({ x: 0, y: 0 })
const canvasSize = ref(props.canvasSize)
watch(
  () => canvasSize.value,
  () => {
    emit('getcanvasSize', canvasSize.value)
  }
)
watch(
  () => props.canvasSize,
  () => {
    canvasSize.value = props.canvasSize
  }
)
// 平移状态
const isPanning = ref(false)
const panStartPos = ref({ x: 0, y: 0 })

// 空格键状态
const spaceKeyPressed = ref(false)

// 选择框状态
const isSelecting = ref(false)
const selectionBox = ref({
  show: false,
  x: 0,
  y: 0,
  width: 0,
  height: 0,
})

// 大小调整状态
const isResizing = ref(false)
const resizeStartPos = ref({ x: 0, y: 0 })
const resizeStartSize = ref({ width: 0, height: 0 })
const resizeDirection = ref('')

// 剪贴板状态
const clipboard = ref(null)

// 画布容器和画布引用
const canvasContainer = ref(null)
const canvas = ref(null)

// 连线相关状态
const isDrawingConnection = ref(false)
const connectionSourceId = ref('')
const connectionTempPos = ref({ x: 0, y: 0 })

// 新增：对齐校准线相关状态
const alignmentGuides = ref([])
const alignmentThreshold = ref(8) // 对齐阈值，单位px
const snapToGuide = ref(true) // 是否开启吸附功能
// 设置对其根据多选的节点进行对其
const setAlignment = (value) => {
  const selectedNodes = nodes.value.filter((n) => selectedNodeIds.value.includes(n.id))
  // 如果选择的是左则直接按照最x最小的那个对其
  if (value === 'left') {
    selectedNodes.sort((a, b) => a.x - b.x)
    selectedNodes.map((val) => {
      val.x = selectedNodes[0].x
    })
  }
  if (value === 'right') {
    selectedNodes.sort((a, b) => a.x - b.x)
    selectedNodes.map((val) => {
      val.x = selectedNodes[selectedNodes.length - 1].x
    })
  }
  if (value === 'top') {
    selectedNodes.sort((a, b) => a.y - b.y)
    selectedNodes.map((val) => {
      val.y = selectedNodes[0].y
    })
  }
  if (value === 'bottom') {
    selectedNodes.sort((a, b) => a.y - b.y)
    selectedNodes.map((val) => {
      val.y = selectedNodes[selectedNodes.length - 1].y
    })
  }

  saveStateToHistory()
}
// 设置多个图形的宽高-节流写法
const setChange = () => {
  const selectedNodes = nodes.value.filter((n) => selectedNodeIds.value.includes(n.id))
  selectedNodes.forEach((node) => {
    node.width = nodeWidth.value
    node.height = nodeHeight.value
  })
}
// 获取画布位置
const getCanvasPosition = (clientX, clientY) => {
  const rect = canvasContainer.value.getBoundingClientRect()
  return {
    x: (clientX - rect.left - canvasOffset.value.x) / canvasScale.value,
    y: (clientY - rect.top - canvasOffset.value.y) / canvasScale.value,
  }
}

const startDrag = (event, node) => {
  event.dataTransfer.setData('text/plain', JSON.stringify(node))
  event.dataTransfer.effectAllowed = 'copy'
}
// 点击图层选中节点
const NodeDrag = (value) => {
  const evenets = document.getElementById(value.id)

  // startNodeDrag(evenets,value)
  if (selectedNodeIds.value.includes(value.id)) {
    // 删除selectedNodeIds.value中的id
    const index = selectedNodeIds.value.indexOf(value.id)
    selectedNodeIds.value.splice(index, 1)
  } else {
    selectedNodeIds.value.push(value.id)
  }
}
const startNodeDrag = (event, node) => {
  if (props.isPview) return
  if (event.button === 2) return

  if (spaceKeyPressed.value || isSelecting.value || isResizing.value || isDrawingConnection.value)
    return

  if (!event.ctrlKey && !event.shiftKey && !selectedNodeIds.value.includes(node.id)) {
    selectedNodeIds.value = [node.id]
  } else if ((event.ctrlKey || event.shiftKey) && !selectedNodeIds.value.includes(node.id)) {
    selectedNodeIds.value.push(node.id)
  }

  draggingNodeIds.value = [...selectedNodeIds.value]

  nodeStartPositions.value = {}
  selectedNodeIds.value.forEach((id) => {
    const n = nodes.value.find((n) => n.id === id)
    if (n) {
      nodeStartPositions.value[id] = { x: n.x, y: n.y }
    }
  })

  const pos = getCanvasPosition(event.clientX, event.clientY)
  dragStartPos.value = {
    x: pos.x,
    y: pos.y,
  }

  document.addEventListener('mousemove', handleDragMove)
  document.addEventListener('mouseup', stopDrag)
}

// 新增：检查对齐并返回调整后的位置和校准线
const checkAlignment = (nodesBeingDragged) => {
  const guides = []
  const otherNodes = nodes.value.filter(
    (n) => !nodesBeingDragged.some((dragged) => dragged.id === n.id)
  )

  nodesBeingDragged.forEach((draggedNode) => {
    const dragged = {
      left: draggedNode.x,
      right: draggedNode.x + draggedNode.width,
      top: draggedNode.y,
      bottom: draggedNode.y + draggedNode.height,
      centerX: draggedNode.x + draggedNode.width / 2,
      centerY: draggedNode.y + draggedNode.height / 2,
    }

    // 1. 先检查与画布边界的对齐
    // 画布中心线对齐
    if (Math.abs(dragged.centerX - canvasSize.value.width / 2) <= alignmentThreshold.value) {
      guides.push({
        id: `guide-v-canvas-center-${draggedNode.id}`,
        left: canvasSize.value.width / 2,
        top: 0,
        width: 2,
        height: canvasSize.value.height,
        color: 'rgba(255, 0, 255, 0.7)', // 紫色表示画布中心线
      })
      if (snapToGuide.value) {
        draggedNode.x = canvasSize.value.width / 2 - draggedNode.width / 2
      }
    }

    if (Math.abs(dragged.centerY - canvasSize.value.height / 2) <= alignmentThreshold.value) {
      guides.push({
        id: `guide-h-canvas-center-${draggedNode.id}`,
        left: 0,
        top: canvasSize.value.height / 2,
        width: canvasSize.value.width,
        height: 2,
        color: 'rgba(255, 0, 255, 0.7)', // 紫色表示画布中心线
      })
      if (snapToGuide.value) {
        draggedNode.y = canvasSize.value.height / 2 - draggedNode.height / 2
      }
    }

    // 2. 检查与其他节点的对齐
    otherNodes.forEach((otherNode) => {
      const other = {
        left: otherNode.x,
        right: otherNode.x + otherNode.width,
        top: otherNode.y,
        bottom: otherNode.y + otherNode.height,
        centerX: otherNode.x + otherNode.width / 2,
        centerY: otherNode.y + otherNode.height / 2,
      }

      // 检查所有可能的对齐组合
      const alignments = [
        // 水平对齐 (Y轴)
        {
          condition: Math.abs(dragged.top - other.top) <= alignmentThreshold.value,
          guide: {
            id: `guide-h-top-${draggedNode.id}-${otherNode.id}`,
            left: Math.min(dragged.left, other.left),
            top: other.top,
            width: Math.max(dragged.right, other.right) - Math.min(dragged.left, other.left),
            height: 2,
            color: 'rgba(0, 200, 0, 0.7)',
          },
          snap: () => {
            draggedNode.y = other.top
          },
        },
        {
          condition: Math.abs(dragged.bottom - other.bottom) <= alignmentThreshold.value,
          guide: {
            id: `guide-h-bottom-${draggedNode.id}-${otherNode.id}`,
            left: Math.min(dragged.left, other.left),
            top: other.bottom,
            width: Math.max(dragged.right, other.right) - Math.min(dragged.left, other.left),
            height: 2,
            color: 'rgba(0, 200, 0, 0.7)',
          },
          snap: () => {
            draggedNode.y = other.bottom - draggedNode.height
          },
        },
        {
          condition: Math.abs(dragged.centerY - other.centerY) <= alignmentThreshold.value,
          guide: {
            id: `guide-h-center-${draggedNode.id}-${otherNode.id}`,
            left: Math.min(dragged.left, other.left),
            top: other.centerY,
            width: Math.max(dragged.right, other.right) - Math.min(dragged.left, other.left),
            height: 2,
            color: 'rgba(255, 0, 0, 0.7)',
          },
          snap: () => {
            draggedNode.y = other.centerY - draggedNode.height / 2
          },
        },
        // 垂直对齐 (X轴)
        {
          condition: Math.abs(dragged.left - other.left) <= alignmentThreshold.value,
          guide: {
            id: `guide-v-left-${draggedNode.id}-${otherNode.id}`,
            left: other.left,
            top: Math.min(dragged.top, other.top),
            height: Math.max(dragged.bottom, other.bottom) - Math.min(dragged.top, other.top),
            width: 2,
            color: 'rgba(0, 200, 0, 0.7)',
          },
          snap: () => {
            draggedNode.x = other.left
          },
        },
        {
          condition: Math.abs(dragged.right - other.right) <= alignmentThreshold.value,
          guide: {
            id: `guide-v-right-${draggedNode.id}-${otherNode.id}`,
            left: other.right,
            top: Math.min(dragged.top, other.top),
            height: Math.max(dragged.bottom, other.bottom) - Math.min(dragged.top, other.top),
            width: 2,
            color: 'rgba(0, 200, 0, 0.7)',
          },
          snap: () => {
            draggedNode.x = other.right - draggedNode.width
          },
        },
        {
          condition: Math.abs(dragged.centerX - other.centerX) <= alignmentThreshold.value,
          guide: {
            id: `guide-v-center-${draggedNode.id}-${otherNode.id}`,
            left: other.centerX,
            top: Math.min(dragged.top, other.top),
            height: Math.max(dragged.bottom, other.bottom) - Math.min(dragged.top, other.top),
            width: 2,
            color: 'rgba(255, 0, 0, 0.7)',
          },
          snap: () => {
            draggedNode.x = other.centerX - draggedNode.width / 2
          },
        },
        // 新增：水平对齐的左边和右边对齐线
        {
          condition: Math.abs(dragged.left - other.right) <= alignmentThreshold.value,
          guide: {
            id: `guide-h-left-right-${draggedNode.id}-${otherNode.id}`,
            left: other.right,
            top: Math.min(dragged.top, other.top),
            height: Math.max(dragged.bottom, other.bottom) - Math.min(dragged.top, other.top),
            width: 2,
            color: 'rgba(255, 165, 0, 0.7)', // 橙色表示左边对齐右边
          },
          snap: () => {
            draggedNode.x = other.right
          },
        },
        {
          condition: Math.abs(dragged.right - other.left) <= alignmentThreshold.value,
          guide: {
            id: `guide-h-right-left-${draggedNode.id}-${otherNode.id}`,
            left: other.left,
            top: Math.min(dragged.top, other.top),
            height: Math.max(dragged.bottom, other.bottom) - Math.min(dragged.top, other.top),
            width: 2,
            color: 'rgba(255, 165, 0, 0.7)', // 橙色表示右边对齐左边
          },
          snap: () => {
            draggedNode.x = other.left - draggedNode.width
          },
        },
        // 新增：从下往上的对齐检查
        {
          condition: Math.abs(dragged.top - other.bottom) <= alignmentThreshold.value,
          guide: {
            id: `guide-h-top-bottom-${draggedNode.id}-${otherNode.id}`,
            left: Math.min(dragged.left, other.left),
            top: other.bottom,
            width: Math.max(dragged.right, other.right) - Math.min(dragged.left, other.left),
            height: 2,
            color: 'rgba(0, 150, 255, 0.7)', // 蓝色表示特殊对齐
          },
          snap: () => {
            draggedNode.y = other.bottom
          },
        },
        {
          condition: Math.abs(dragged.bottom - other.top) <= alignmentThreshold.value,
          guide: {
            id: `guide-h-bottom-top-${draggedNode.id}-${otherNode.id}`,
            left: Math.min(dragged.left, other.left),
            top: other.top,
            width: Math.max(dragged.right, other.right) - Math.min(dragged.left, other.left),
            height: 2,
            color: 'rgba(0, 150, 255, 0.7)', // 蓝色表示特殊对齐
          },
          snap: () => {
            draggedNode.y = other.top - draggedNode.height
          },
        },
      ]

      // 检查所有对齐条件
      alignments.forEach((alignment) => {
        if (alignment.condition) {
          guides.push(alignment.guide)
          if (snapToGuide.value) {
            alignment.snap()
          }
        }
      })
    })
  })

  return guides
}

const handleDragMove = (event) => {
  if (draggingNodeIds.value.length === 0) return

  const pos = getCanvasPosition(event.clientX, event.clientY)

  const dx = pos.x - dragStartPos.value.x
  const dy = pos.y - dragStartPos.value.y

  // 先计算临时位置
  const nodesBeingDragged: {
    id: never
    x: number
    y: number
    width: number
    height: number
    color: string
    type: string
    label: string
    _tempX: number
    _tempY: number
  }[] = []
  draggingNodeIds.value.forEach((id) => {
    const node = nodes.value.find((n) => n.id === id)
    if (node && nodeStartPositions.value[id]) {
      // 保存原始位置用于可能的对齐调整
      node._tempX = nodeStartPositions.value[id].x + dx
      node._tempY = nodeStartPositions.value[id].y + dy
      nodesBeingDragged.push(node)

      emit('handleDragMove', node)
    }
  })

  // 应用临时位置
  nodesBeingDragged.forEach((node) => {
    node.x = node._tempX
    node.y = node._tempY
  })

  // 检查对齐并获取校准线
  let guides = []
  if (snapToGuide.value) {
    guides = checkAlignment(nodesBeingDragged)
  }

  // 更新校准线
  alignmentGuides.value = guides
  // console.log(alignmentGuides.value);

}

const stopDrag = () => {
  draggingNodeIds.value = []
  alignmentGuides.value = [] // 清除校准线
  document.removeEventListener('mousemove', handleDragMove)
  document.removeEventListener('mouseup', stopDrag)
  emit('getNodesValue', nodes.value)
  // 新增：保存状态到历史记录
  saveStateToHistory()
}

const handleDrop = (event) => {
  event.preventDefault()
  const data = event.dataTransfer.getData('text/plain')
  if (!data) return

  try {
    const nodeData = JSON.parse(data)
    const pos = getCanvasPosition(event.clientX, event.clientY)
    // console.log(nodeData)

    const newNode = {
      id: `node-${Date.now()}`,
      ...nodeData,
      label: nodeData.label || '未命名节点' + nodes.value.length,
      x: pos.x - nodeData.width / 2,
      y: pos.y - nodeData.height / 2,
      obj: {},
    }
    // console.log(newNode)

    nodes.value.push(newNode)
    selectNodes.value = newNode
    selectedNodeIds.value = [newNode.id]
    emit('getNodesValue', nodes.value)
    // 新增：保存状态到历史记录
    saveStateToHistory()
  } catch (error) {
    console.error('放置节点失败:', error)
  }
}

const selectNode = (event, node) => {

  if (props.isPview) return
  console.log(props.isPview);

  // 选中节点时取消选中连线
  selectedConnectionId.value = ''

  if (spaceKeyPressed.value || isSelecting.value || isResizing.value || isDrawingConnection.value)
    return
  selectNodes.value = node

  if (event.ctrlKey || event.shiftKey) {
    if (selectedNodeIds.value.includes(node.id)) {
      // 保持原有逻辑
    } else {
      selectedNodeIds.value.push(node.id)
    }
  } else {
    selectedNodeIds.value = [node.id]
  }
}

const startResize = (event, node, direction) => {
  if (selectedNodeIds.value.length !== 1 || isDrawingConnection.value) return

  isResizing.value = true
  resizeDirection.value = direction

  const pos = getCanvasPosition(event.clientX, event.clientY)
  resizeStartPos.value = { x: pos.x, y: pos.y }
  resizeStartSize.value = { width: node.width, height: node.height }

  document.addEventListener('mousemove', handleResize)
  document.addEventListener('mouseup', stopResize)
  event.stopPropagation()
}

const handleResize = (event) => {
  if (!isResizing.value) return

  const pos = getCanvasPosition(event.clientX, event.clientY)
  const dx = pos.x - resizeStartPos.value.x
  const dy = pos.y - resizeStartPos.value.y

  const node = nodes.value.find((n) => n.id === selectedNodeIds.value[0])
  if (!node) return

  const aspectRatio = resizeStartSize.value.width / resizeStartSize.value.height

  switch (resizeDirection.value) {
    case 'se':
      if (event.ctrlKey) {
        const newWidth = Math.max(20, resizeStartSize.value.width + dx)
        const newHeight = newWidth / aspectRatio
        node.width = newWidth
        node.height = newHeight
      } else {
        node.width = Math.max(20, resizeStartSize.value.width + dx)
        node.height = Math.max(20, resizeStartSize.value.height + dy)
      }
      break
    case 'sw':
      if (event.ctrlKey) {
        const newWidth = Math.max(20, resizeStartSize.value.width - dx)
        const newHeight = newWidth / aspectRatio
        node.width = newWidth
        node.height = newHeight
        node.x = resizeStartPos.value.x - (node.width - resizeStartSize.value.width)
      } else {
        node.width = Math.max(20, resizeStartSize.value.width - dx)
        node.height = Math.max(20, resizeStartSize.value.height + dy)
        node.x = resizeStartPos.value.x - (node.width - resizeStartSize.value.width)
      }
      break
    case 'ne':
      if (event.ctrlKey) {
        const newWidth = Math.max(20, resizeStartSize.value.width + dx)
        const newHeight = newWidth / aspectRatio
        node.width = newWidth
        node.height = newHeight
        node.y = resizeStartPos.value.y - (node.height - resizeStartSize.value.height)
      } else {
        node.width = Math.max(20, resizeStartSize.value.width + dx)
        node.height = Math.max(20, resizeStartSize.value.height - dy)
        node.y = resizeStartPos.value.y - (node.height - resizeStartSize.value.height)
      }
      break
    case 'nw':
      if (event.ctrlKey) {
        const newWidth = Math.max(20, resizeStartSize.value.width - dx)
        const newHeight = newWidth / aspectRatio
        node.width = newWidth
        node.height = newHeight
        node.x = resizeStartPos.value.x - (node.width - resizeStartSize.value.width)
        node.y = resizeStartPos.value.y - (node.height - resizeStartSize.value.height)
      } else {
        node.width = Math.max(20, resizeStartSize.value.width - dx)
        node.height = Math.max(20, resizeStartSize.value.height - dy)
        node.x = resizeStartPos.value.x - (node.width - resizeStartSize.value.width)
        node.y = resizeStartPos.value.y - (node.height - resizeStartSize.value.height)
      }
      break
  }

  // 调整大小时也检查对齐
  if (snapToGuide.value && node) {
    const guides = checkAlignment([node])
    alignmentGuides.value = guides
  }
}

const stopResize = () => {
  isResizing.value = false
  resizeDirection.value = ''
  alignmentGuides.value = [] // 清除校准线
  document.removeEventListener('mousemove', handleResize)
  document.removeEventListener('mouseup', stopResize)
  // 新增：保存状态到历史记录
  saveStateToHistory()
}
// 双击节点
const editNode = (node) => {
  // 双击节点时取消选中连线
  selectedConnectionId.value = ''
  // 触发编辑事件
  emit('editNode', node)
}
const startSelection = (event) => {
  if (props.isPview) return
  // 开始框选时取消选中连线
  selectedConnectionId.value = ''

  if (
    spaceKeyPressed.value ||
    event.target !== canvas.value ||
    isResizing.value ||
    isDrawingConnection.value
  )
    return

  isSelecting.value = true
  const pos = getCanvasPosition(event.clientX, event.clientY)
  selectionBox.value = {
    show: true,
    x: pos.x,
    y: pos.y,
    width: 0,
    height: 0,
  }

  document.addEventListener('mousemove', updateSelection)
  document.addEventListener('mouseup', endSelection)
}

const selectionBoxs = ref({})
const updateSelection = (event) => {
  if (!isSelecting.value) return
  const pos = getCanvasPosition(event.clientX, event.clientY)

  selectionBoxs.value = {
    show: true,
    x: pos.x < selectionBox.value.x ? pos.x : selectionBox.value.x,
    y: pos.y < selectionBox.value.y ? pos.y : selectionBox.value.y,
    width: Math.abs(pos.x - selectionBox.value.x),
    height: Math.abs(pos.y - selectionBox.value.y),
    // height: pos.y - selectionBox.value.y
  }
  selectionBox.value = {
    show: true,
    x: selectionBox.value.x,
    y: selectionBox.value.y,
    width: pos.x - selectionBox.value.x,
    height: pos.y - selectionBox.value.y,
  }

  const boxLeft = Math.min(selectionBox.value.x, selectionBox.value.x + selectionBox.value.width)
  const boxTop = Math.min(selectionBox.value.y, selectionBox.value.y + selectionBox.value.height)
  const boxRight = Math.max(selectionBox.value.x, selectionBox.value.x + selectionBox.value.width)
  const boxBottom = Math.max(selectionBox.value.y, selectionBox.value.y + selectionBox.value.height)

  const selectedIds = []
  nodes.value.forEach((node) => {
    const nodeLeft = node.x
    const nodeTop = node.y
    const nodeRight = node.x + node.width
    const nodeBottom = node.y + node.height

    if (nodeRight > boxLeft && nodeLeft < boxRight && nodeBottom > boxTop && nodeTop < boxBottom) {
      selectedIds.push(node.id)
    }
  })
  selectedNodeIds.value = selectedIds
}

const endSelection = () => {
  isSelecting.value = false
  selectionBox.value.show = false
  selectionBoxs.value = {}
  document.removeEventListener('mousemove', updateSelection)
  document.removeEventListener('mouseup', endSelection)
}

const handleCanvasClick = (event) => {
  // 点击画布空白处取消选中连线
  if (event.target === canvas.value) {
    selectedConnectionId.value = ''
  }

  if (isDrawingConnection.value) {
    isDrawingConnection.value = false
    connectionSourceId.value = ''
    return
  }

  if (
    event.target === canvas.value &&
    event.ctrlKey &&
    !spaceKeyPressed.value &&
    !isResizing.value
  ) {
    startSelection(event)
  } else if (
    event.target === canvas.value &&
    !spaceKeyPressed.value &&
    !isSelecting.value &&
    !event.ctrlKey &&
    !isResizing.value
  ) {
    selectedNodeIds.value = []
    nodeWidth.value = ''
    nodeHeight.value = ''
    alignment.value = ''
  }
}

const copyNode = () => {
  if (selectedNodeIds.value.length === 0) return

  const node = nodes.value.find((n) => n.id === selectedNodeIds.value[0])
  if (node) {
    clipboard.value = JSON.parse(JSON.stringify(node))
    clipboard.value.label = clipboard.value.label + '-copy'
    emit('copyNode', clipboard.value)

  }
}

const pasteNode = () => {
  if (!clipboard.value) return

  const newNode = {
    ...JSON.parse(JSON.stringify(clipboard.value)),
    id: `node-${Date.now()}`,
    x: clipboard.value.x + 20,
    y: clipboard.value.y + 20,
  }
  // console.log(newNode)

  nodes.value.push(newNode)
  selectedNodeIds.value = [newNode.id]
  // 新增：保存状态到历史记录
  saveStateToHistory()
}
// 删除节点
const deleteSelectedNodes = () => {
  if (selectedNodeIds.value.length === 0) return
  const deletedNodes = nodes.value.filter((node) => selectedNodeIds.value.includes(node.id))

  nodes.value = nodes.value.filter((node) => !selectedNodeIds.value.includes(node.id))
  // 拿到删除的全部节点
  // console.log(deletedNodes);

  emit('getNodesValue', nodes.value)
  emit('delNodes', deletedNodes)
  connections.value = connections.value.filter(
    (conn) =>
      !selectedNodeIds.value.includes(conn.source) && !selectedNodeIds.value.includes(conn.target)
  )

  selectedNodeIds.value = []
  emit('getConnectionsValue', connections.value)
  // 新增：保存状态到历史记录
  saveStateToHistory()
}

// 删除选中的连线
const deleteSelectedConnection = () => {
  if (!selectedConnectionId.value) return

  connections.value = connections.value.filter((conn) => conn.id !== selectedConnectionId.value)
  selectedConnectionId.value = ''
  emit('getConnectionsValue', connections.value)
  // 新增：保存状态到历史记录
  saveStateToHistory()
}

const handleWheel = (event) => {
  event.preventDefault()
  if (props.isPview && !props.isZoom) return

  const rect = canvasContainer.value.getBoundingClientRect()
  const mouseX = event.clientX - rect.left
  const mouseY = event.clientY - rect.top

  const contentX = (mouseX - canvasOffset.value.x) / canvasScale.value
  const contentY = (mouseY - canvasOffset.value.y) / canvasScale.value

  const delta = -event.deltaY
  const scaleFactor = delta > 0 ? 1.1 : 0.9
  const newScale = Math.max(0.1, Math.min(5, canvasScale.value * scaleFactor))

  canvasOffset.value.x = mouseX - contentX * newScale
  canvasOffset.value.y = mouseY - contentY * newScale

  canvasScale.value = newScale
}

const startPan = (event) => {
  if (
    spaceKeyPressed.value &&
    event.button === 0 &&
    !isResizing.value &&
    !isDrawingConnection.value
  ) {
    isPanning.value = true
    panStartPos.value = {
      x: event.clientX - canvasOffset.value.x,
      y: event.clientY - canvasOffset.value.y,
    }
    event.preventDefault()
  }
}

const handlePan = (event) => {
  if (isPanning.value) {
    canvasOffset.value.x = event.clientX - panStartPos.value.x
    canvasOffset.value.y = event.clientY - panStartPos.value.y
  } else if (isDrawingConnection.value) {
    const pos = getCanvasPosition(event.clientX, event.clientY)
    connectionTempPos.value = pos
  }
}

const stopPan = () => {
  isPanning.value = false
}

const handleKeyDown = (event) => {
  // 新增：处理撤回和重做快捷键
  if (event.ctrlKey || event.metaKey) {
    if (props.isPview) return
    if (event.key.toLowerCase() === 'z') {
      // 撤销
      undo()
      event.preventDefault()
      return
    } else if (event.key.toLowerCase() === 'y') {
      // 重做
      redo()
      event.preventDefault()
      return
    }
  }

  // 删除选中的连线（Delete键）
  if (event.key === 'Delete' && selectedConnectionId.value) {
    if (props.isPview) return
    deleteSelectedConnection()
    event.preventDefault()

    return
  }

  if (event.code === 'Space') {
    if (props.isPview && !props.isPanning) return
    spaceKeyPressed.value = true
    event.preventDefault()
  }

  // 新增：按Alt键临时禁用吸附功能
  if (event.key === 'Alt') {
    snapToGuide.value = false
  }

  if (event.ctrlKey || event.metaKey) {
    if (props.isPview) return
    switch (event.key.toLowerCase()) {
      case 'c':
        copyNode()
        event.preventDefault()
        break
      case 'v':
        pasteNode()
        event.preventDefault()
        break
      case 'd':
        copyNode()
        pasteNode()
        event.preventDefault()
        break
    }
  }

  if (event.key === 'Backspace') {
    if (props.isPview) return
    const activeElement = document.activeElement
    const isInputFocused = activeElement.tagName === 'INPUT' || activeElement.tagName === 'TEXTAREA'

    if (!isInputFocused) {
      deleteSelectedNodes()
      event.preventDefault()
    }
  }
}

const handleKeyUp = (event) => {
  if (event.code === 'Space') {
    if (props.isPview) return
    spaceKeyPressed.value = false
    isPanning.value = false
  }

  // 释放Alt键时重新启用吸附功能
  if (event.key === 'Alt') {
    if (props.isPview) return
    snapToGuide.value = true
  }
}

const zoomIn = () => {
  const rect = canvasContainer.value.getBoundingClientRect()
  const centerX = rect.width / 2
  const centerY = rect.height / 2

  const contentX = (centerX - canvasOffset.value.x) / canvasScale.value
  const contentY = (centerY - canvasOffset.value.y) / canvasScale.value

  const newScale = Math.min(5, canvasScale.value + 0.1)
  canvasOffset.value.x = centerX - contentX * newScale
  canvasOffset.value.y = centerY - contentY * newScale

  canvasScale.value = newScale
}

const zoomOut = () => {
  const rect = canvasContainer.value.getBoundingClientRect()
  const centerX = rect.width / 2
  const centerY = rect.height / 2

  const contentX = (centerX - canvasOffset.value.x) / canvasScale.value
  const contentY = (centerY - canvasOffset.value.y) / canvasScale.value

  const newScale = Math.max(0.1, canvasScale.value - 0.1)
  canvasOffset.value.x = centerX - contentX * newScale
  canvasOffset.value.y = centerY - contentY * newScale

  canvasScale.value = newScale
}

const resetZoom = () => {
  canvasScale.value = 1
  canvasOffset.value = { x: 0, y: 0 }
}

const startConnection = (sourceNode) => {
  if (!props.isConnectionType) return
  
  isSelecting.value = false
  isResizing.value = false
  isPanning.value = false
  // 开始连线时取消选中连线
  selectedConnectionId.value = ''

  isDrawingConnection.value = true
  connectionSourceId.value = sourceNode.id

  const rect = canvasContainer.value.getBoundingClientRect()
  const pos = getCanvasPosition(event.clientX, event.clientY)
  connectionTempPos.value = pos

  document.addEventListener('mousemove', updateTemporaryConnection)
}

const updateTemporaryConnection = (event) => {
  if (!isDrawingConnection.value) return

  const pos = getCanvasPosition(event.clientX, event.clientY)
  connectionTempPos.value = pos
}

const endConnection = (event) => {
  if (!isDrawingConnection.value) return

  document.removeEventListener('mousemove', updateTemporaryConnection)

  const pos = getCanvasPosition(event.clientX, event.clientY)
  const targetNode = nodes.value.find(
    (node) =>
      pos.x >= node.x &&
      pos.x <= node.x + node.width &&
      pos.y >= node.y &&
      pos.y <= node.y + node.height &&
      node.id !== connectionSourceId.value
  )

  if (targetNode) {
    connections.value.push({
      id: `conn-${Date.now()}`,
      source: connectionSourceId.value,
      target: targetNode.id,
    })
    emit('getConnectionsValue', connections.value)
    // 新增：保存状态到历史记录
    saveStateToHistory()
  }

  isDrawingConnection.value = false
  connectionSourceId.value = ''
}

const getNodeCenter = (nodeId) => {
  const node = nodes.value.find((n) => n.id === nodeId)
  if (!node) return { x: 0, y: 0 }

  return {
    x: node.x + node.width / 2,
    y: node.y + node.height / 2,
  }
}

// 根据选择的类型获取连接线路径
const getConnectionPathByType = (connection) => {
  if (connectionType.value === 'mindmap') {
    return getMindmapConnectionPath(connection)
  }
  return getCurveConnectionPath(connection)
}

// 原有曲线连接线路径
const getCurveConnectionPath = (connection) => {
  const sourceCenter = getNodeCenter(connection.source)
  const targetCenter = getNodeCenter(connection.target)

  const midX = (sourceCenter.x + targetCenter.x) / 2

  return `M ${sourceCenter.x} ${sourceCenter.y}
          C ${midX} ${sourceCenter.y},
            ${midX} ${targetCenter.y},
            ${targetCenter.x} ${targetCenter.y}`
}

// 脑图折线连接线路径
const getMindmapConnectionPath = (connection) => {
  const sourceCenter = getNodeCenter(connection.source)
  const targetCenter = getNodeCenter(connection.target)

  // 脑图风格折线：从源节点向右延伸，然后垂直连接到目标节点同一水平位置，再连接到目标节点
  const horizontalOffset = 50 // 水平延伸距离
  const sourceX = sourceCenter.x + horizontalOffset
  const targetX = targetCenter.x > sourceX ? targetCenter.x - horizontalOffset : sourceX

  return `M ${sourceCenter.x} ${sourceCenter.y}
          L ${sourceX} ${sourceCenter.y}
          L ${sourceX} ${targetCenter.y}
          L ${targetCenter.x} ${targetCenter.y}`
}
// 根据id设置节点的配置
const setNodesConfig = (id, type, value) => {
  const node = nodes.value.find((n) => n.id === id)
  if (node) {
    // 设置节点的配置
    node[type] = value
  }
  emit('getNodesValue', nodes.value)
}
const getTemporaryConnectionPath = () => {
  const sourceCenter = getNodeCenter(connectionSourceId.value)

  // 根据当前选中的连线类型绘制临时连线
  if (connectionType.value === 'mindmap') {
    const horizontalOffset = 50
    const sourceX = sourceCenter.x + horizontalOffset

    return `M ${sourceCenter.x} ${sourceCenter.y}
            L ${sourceX} ${sourceCenter.y}
            L ${sourceX} ${connectionTempPos.value.y}
            L ${connectionTempPos.value.x} ${connectionTempPos.value.y}`
  } else {
    const midX = (sourceCenter.x + connectionTempPos.value.x) / 2

    return `M ${sourceCenter.x} ${sourceCenter.y}
            C ${midX} ${sourceCenter.y},
              ${midX} ${connectionTempPos.value.y},
              ${connectionTempPos.value.x} ${connectionTempPos.value.y}`
  }
}

// 选中连线
const selectConnection = (connectionId) => {
  // 选中连线时取消选中节点
  selectedNodeIds.value = []
  selectedConnectionId.value = connectionId
}

watch(
  nodes,
  () => {
    // 节点移动时自动更新连线
  },
  { deep: true }
)

// 监听连线类型变化，更新连线显示
watch(connectionType, () => {
  // 触发重绘
})

onMounted(() => {
  document.querySelector('.flow-editor').focus()
})
const saveNodes = () => {
  emit('saveNodes', nodes.value)
}
const getNodes = () => {
  emit('getNodes', nodes.value)
}
onUnmounted(() => {
  nodes.value = []
  connections.value = []
  emit('getNodesValue', nodes.value)
  emit('getConnectionsValue', connections.value)
  // console.log(nodes.value)

  document.removeEventListener('mousemove', handleDragMove)
  document.removeEventListener('mouseup', stopDrag)
  document.removeEventListener('mousemove', updateSelection)
  document.removeEventListener('mouseup', endSelection)
  document.removeEventListener('mousemove', handleResize)
  document.removeEventListener('mouseup', stopResize)
  document.removeEventListener('keydown', handleKeyDown)
  document.removeEventListener('keyup', handleKeyUp)
  document.removeEventListener('mousemove', updateTemporaryConnection)
})
// 强制canvas缩放比例显示全部
const canvasInit = () => {
  // 拿到canvas的父元素的宽高
  const canvasContainer = canvas.value.parentElement
  const canvasContainerWidth = canvasContainer.offsetWidth
  const canvasContainerHeight = canvasContainer.offsetHeight
  // 计算缩放比例
  // 通过canvasContainerWidth，canvasContainerHeight以及canvasSize计算出来宽高 让canvas缩放比例显示全部
  const canvasScale2 = Math.min(
    canvasContainerWidth / canvasSize.value.width,
    canvasContainerHeight / canvasSize.value.height,
  )
  
  // 设置画布缩放
  canvas.value.style.transform = `scale(${canvasScale2})`
  canvasScale.value = canvasScale2
  const height = canvasContainer.parentElement.parentElement.parentElement.offsetHeight

  // canvasContainer.value.style.height = height + 'px'
}
defineExpose({
  startDrag,
  setNodesConfig,
  canvasInit
})
</script>

<style>
@import url('./index.css');
</style>
